
// GraphViewDlg.cpp : implementation file
//

#include "stdafx.h"
#include "GraphView.h"
#include "GraphViewDlg.h"
#include "afxdialogex.h"

#include "StationDlg.h"
#include "LinkOptionsDlg.h"
#include "GraphOptions.h"
#include "pugixml/pugixml.hpp"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CGraphViewDlg dialog



CGraphViewDlg::CGraphViewDlg(CWnd* pParent /*=NULL*/)
	: CResizeDlgCtrl(CGraphViewDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CGraphViewDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CGraphViewDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
    ON_COMMAND(ID_ADD_STATION, &CGraphViewDlg::OnAddStation)
    ON_COMMAND(ID_ADD_LINK, &CGraphViewDlg::OnAddLink)
    ON_MESSAGE(DM_GETDEFID, &CGraphViewDlg::OnGetDefID)
    ON_COMMAND(ID_FILE_OPEN, &CGraphViewDlg::OnFileOpen)
    ON_COMMAND(ID_FILE_EXIT, &CGraphViewDlg::OnAppExit)
    ON_WM_SIZE()
	ON_WM_MOUSEMOVE()
	ON_WM_MOUSEHWHEEL()
	ON_WM_LBUTTONDOWN()
    ON_COMMAND(ID_GENERATE_RANDOMGRAPH, &CGraphViewDlg::OnGenerate)
END_MESSAGE_MAP()


// CGraphViewDlg message handlers

BOOL CGraphViewDlg::OnInitDialog()
{
	CResizeDlgCtrl::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}
	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big ic
	SetIcon(m_hIcon, FALSE);		// Set small icon


	// TODO: Add extra initialization here

    _graph.CreateFromStatic(IDC_GRAPH,this);
    _tableView.CreateFromStatic(IDC_TABLE_VIEW,this);

    getDefaultWindowAndChildData();

    setChildExpandable(IDC_GRAPH,TRUE,TRUE);
    setChildExpandable(IDC_TABLE_VIEW,TRUE,TRUE);

    setChildXPosition(IDC_GRAPH,ALIGNMENT_MasterID_DefWin,ALIGNMENT_AXIS_VertLeft,ALIGNMENT_AXIS_VertLeft);
    //setChildYPosition(IDC_GRAPH,IDC_TABLE_VIEW,ALIGNMENT_AXIS_HorUp,ALIGNMENT_AXIS_HorDown);

    setChildXPosition(IDC_TABLE_VIEW,ALIGNMENT_MasterID_DefWin,ALIGNMENT_AXIS_VertLeft,ALIGNMENT_AXIS_VertLeft);
    setChildYPosition(IDC_TABLE_VIEW,IDC_GRAPH,ALIGNMENT_AXIS_HorUp,ALIGNMENT_AXIS_HorDown);
    prepaireChildrenForResize();

    CMenu menu;
    menu.LoadMenu(IDR_MENU1);
    SetMenu(&menu);

	_graph.AddTableView(&_tableView);

    return TRUE;  // return TRUE  unless you set the focus to a control
}

void CGraphViewDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CGraphViewDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CGraphViewDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

LRESULT CGraphViewDlg::OnGetDefID(WPARAM , LPARAM lp)
{
    return MAKELONG(0,DC_HASDEFID);
}

void CGraphViewDlg::OnAddStation()
{
    CStationDlg dlg;

    if (dlg.DoModal() == IDOK)
    {
        Station* pNewStation = new Station(dlg.Longitutde(),dlg.Latitude(),dlg._strStationName,dlg._strLine);
        _graph.AddStation(pNewStation,pNewStation);
    }
}


void CGraphViewDlg::OnAddLink()
{
    CLinkOptionsDlg dlg;

    if (dlg.DoModal() == IDOK)
    {
        _graph.AddLink(_wtoi(dlg._strStartStation),_wtoi(dlg._strEndStation));
        _graph.RedrawWindow();
        if (!_graphFile.IsEmpty())
        {
            pugi::xml_document xmlDoc;
            pugi::xml_parse_result result = xmlDoc.load_file(_graphFile);
            if (result.status != pugi::status_ok)
            {
                TRACE(_T("Error opening XML stations file : %s"),result.description());
                return;
            }
            pugi::xpath_node xmlLink = xmlDoc.select_single_node(_T("StationList/LinkList")); 
            pugi::xml_node xmlNodeLink;
            if (xmlLink.node().empty())
            {
                xmlNodeLink = xmlDoc.child(_T("StationList")).append_child(_T("LinkList"));
            }
            else
                xmlNodeLink = xmlLink.node();
            pugi::xml_node xmlNodeId = xmlNodeLink.find_child_by_attribute(_T("Link"),_T("id"),dlg._strStartStation);
            if (xmlNodeId.empty())
            {
                xmlNodeId = xmlNodeLink.append_child(_T("Link"));
                xmlNodeId.append_attribute(_T("id")) = dlg._strStartStation;
            }
            xmlNodeId.append_child(_T("Id")).append_attribute(_T("value")) = dlg._strEndStation;

            //two way
            xmlNodeId = xmlNodeLink.find_child_by_attribute(_T("Link"),_T("id"),dlg._strEndStation);
            if (xmlNodeId.empty())
            {
                xmlNodeId = xmlNodeLink.append_child(_T("Link"));
                xmlNodeId.append_attribute(_T("id")) = dlg._strEndStation;
            }
            xmlNodeId.append_child(_T("Id")).append_attribute(_T("value")) = dlg._strStartStation;
              
            xmlDoc.save_file(_graphFile);            
        }
    }
}


void CGraphViewDlg::OnFileOpen()
{
    CFileDialog  fileDialog (TRUE, _T("xml"), _T("*.xml"), OFN_EXPLORER | OFN_FILEMUSTEXIST| OFN_HIDEREADONLY , _T("Data files (*.xml)|*.csv|All Files (*.*)|*.*||"));

    if (fileDialog.DoModal() == IDOK)
    {
        _graphFile = fileDialog.GetPathName();
        _graph.Load(_graphFile);
    }

}

void CGraphViewDlg::OnAppExit()
{
    PostQuitMessage(0);
}

void CGraphViewDlg::OnMouseMove(UINT nFlags, CPoint point) 
{
	CString s;
	//s.Format(_T("X=%d Y=%d"),point.x,point.y);
	//TRACE(_T("%s\r\n"),(LPCWSTR)s);
	CDialog::OnMouseMove(nFlags, point);
}

BOOL CGraphViewDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
	CDialog::OnMouseWheel(nFlags,zDelta,pt);
	return true;
}

void CGraphViewDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	const Station* pStation = _graph.GetStation(point);
	if (pStation != NULL)
		_tableView.Select(pStation);
	CDialog::OnLButtonDown(nFlags,point);
}
void CGraphViewDlg::OnGenerate()
{
    CFileDialog  fileDialog (TRUE, _T("csv"), _T("*.csv"), OFN_EXPLORER | OFN_FILEMUSTEXIST| OFN_HIDEREADONLY , _T("Data files (*.csv)|*.csv|All Files (*.*)|*.*||"));

    if (fileDialog.DoModal() == IDOK)
    {
        CString strFilePath = fileDialog.GetPathName();

        CStdioFile stdFile(strFilePath,CFile::modeRead);
        CString strStation;
        pugi::xml_document xmlDoc;
        pugi::xml_node xmlStationList = xmlDoc.append_child(_T("StationList"));
        xmlStationList.append_child(_T("InfoList"));
        xmlStationList.append_child(_T("LinkList"));
        xmlStationList = xmlStationList.child(_T("InfoList"));
        int id = 0;
        while (stdFile.ReadString(strStation))
        {
            int iStartPos = 0;
            CString token = strStation.Tokenize(_T(","),iStartPos);
            vector<CString> tokens;
            while (token != _T(""))
            {
                token.Trim();
                tokens.push_back(token);
                token = strStation.Tokenize(_T(","),iStartPos);
            }

            CString strLine;
            int pos = tokens.at(2).Find(_T("Metro"));
            if (pos != -1)
            {
                strLine = tokens.at(2).Mid(pos+6,2);
                int startPos = pos + 9;
                int iCount = tokens.at(2).GetLength() - pos - 4;
                strStation = tokens.at(2).Mid(startPos,iCount);
            }
            else
            {
                strStation = tokens.at(3);
                strLine = tokens.at(2);
            }
            pugi::xml_node nodeStation = xmlStationList.append_child(_T("station"));
            nodeStation.append_attribute(_T("id")) = ++id;
            nodeStation.append_attribute(_T("name")) = strStation;
            nodeStation.append_attribute(_T("line")) = strLine;
            nodeStation.append_attribute(_T("latitude")) = tokens.at(1);
            nodeStation.append_attribute(_T("longitude")) = tokens.at(0);
        }
        xmlDoc.save_file("e:\\Stations.xml");
    }
}
